#include "../include/unrealbot.h"
#include "../include/unrealhandler.h";
//////////////////////////////////////////////////////\
//                                                  \\/
//          Bot implementation;                     ||
//                                                  //\
/////////////////////////////////////////////////////\/

using namespace Glib;

/**constructor
    standard constructor. Builds the gui and saves the connection.
    \arg \c connection a SocketConnection to the gamebots-server.
    It assumes that HELLO_BOT is already recieved.
*/

UnrealBot::UnrealBot(RefPtr<SocketClient>& sockSource, ustring addr, unsigned port ):UnrealNativeBot((UnrealMap*) map){

    Mutex::Lock lock(mutex);
	this->socketSource = sockSource;

	botstream = 0;
	adres = addr;
	this->port = port;
    infos = new HPaned;
	
    /**list of info about  the bot*/
    VBox* infolist = new VBox;

    /**logviewer logging al the events in the bot*/

    ScrolledWindow* fr1 = new ScrolledWindow;
    ScrolledWindow* fr2 = new ScrolledWindow;

    infolist->pack_end(*new Label(name));

    ((HPaned*) infos)->add1(*fr1);
    ((HPaned*) infos)->add2(*fr2);

    fr1->add(*infolist);
    fr2->add(logger   );

    fr1->set_shadow_type(SHADOW_ETCHED_OUT);
    fr2->set_shadow_type(SHADOW_ETCHED_OUT);

    infolist->pack_end(*new Label(string("addr:")));
    logger << "Hi there, i am a new bot";
    /* //logging possibilities
    logger.logRed("red");
    logger.logRed("red and bold", true);
    logger.log("just Bold", true);
    logger.log("plain");
    */
}

bool UnrealBot::round(){
    switch(state){
    case paused:
    case initialized:
        state=running;
        return true;
    case none:
    case connection_error:
        if(!connect()) return false;//quit if connect doesn't work, otherwise continue with connected part
    case connected:
    case running:
        processInput();
    }
    return true;
}

void UnrealBot::processInput(){
    Mutex::Lock l(Mutex);
unsigned matchval;
	botstream->nextMessage();
    cout << botstream->currentMessage()<<endl;
    //cout.flush();
    matchval = botstream->matchVal();
    //cout << matchval <<endl;
    //cout.flush();
   switch (matchval){
       case 'SHS'  ://shs
            logger << "SHS recognized";
            return processInput();
        case 'OFN' ://nfo
            handleNFO();
            return;
        case 'UMS' ://smut
            handleSMUT();
            break;
        case 'ANS' : //snav
            if (!handler->map.finalized){
                handler->map.readInput(*botstream);
                handler->map.finalize();
                handler->mapDraw = new UnrealMapDraw(&handler->map);
                handler->mapDraw->handler = handler;
                handler->botsInspector2->append_page(*handler->mapDraw, "Map");
				handler->botsInspector2->set_tab_detachable(*handler->mapDraw);
				handler->botsInspector2->set_tab_reorderable(*handler->mapDraw);
            }
            break;
        case 'TIS'://sitc
            //TODO: actually read them out
            botstream->readUntil("EITC");
            break;
   }
}

void UnrealBot::handleNFO(){
int i;
for(i=0; i<botstream->fieldCount(); i++){
    string field = (*botstream)[i].first;
    string value = (*botstream)[i].second;
    logger.log(ustring::compose("%1 => %2", field, value));

    //here we can use if, because it's only once per game
        if(field == "Gametype")
            ((UnrealHandler*) handler)->gameInfos.Gametype        = value;
        else if(field == "Level")
            ((UnrealHandler*) handler)->gameInfos.Level           = value;
        else if(field == "RedBaseLocation")
            ((UnrealHandler*) handler)->gameInfos.RedBaseLocation = new UnrealPlace((char*) value.c_str());
        else if(field == "BlueBaseLocation")
            ((UnrealHandler*) handler)->gameInfos.BlueBaseLocation= new UnrealPlace((char*) value.c_str());
        else if(field == "WeaponStay")
            ((UnrealHandler*) handler)->gameInfos.WeaponStay      = value=="True";
        else if(field == "GamePaused")
            ((UnrealHandler*) handler)->gameInfos.GamePaused      = value=="True";
        else if(field == "BotsPaused")
            ((UnrealHandler*) handler)->gameInfos.BotsPaused      = value=="True";
        else if(field == "MaxTeams")
            ((UnrealHandler*) handler)->gameInfos.MaxTeams        = atoi(value.c_str());
        else if(field == "MaxTeamSize")
            ((UnrealHandler*) handler)->gameInfos.MaxTeamSize     = atoi(value.c_str());
    }
}

void UnrealBot::handleSMUT(){
    botstream->readUntil("EMUT");// don't care about mutators for now; just skip to the end of them
}


bool UnrealBot::connect(ustring addr, unsigned port){
    // We connect to the server
		adres = addr;
		port  = port;
		if ( connection && !connection->is_closed() ){
			cout << "connection exists" << endl;
			logger.logRed("connection already exists");
			return false;
		}
		try{
			connection =
				socketSource->connect_to_host(adres, port);
		}
		catch(Gio::Error& e){
			logger.logRed(ustring("connection Failed: ") + e.what());
			return false;
		}
		catch(Glib::Error& e){
			logger.logRed(ustring("connection Failed: ") + e.what());			
			return false;
		}
	
		catch(...){
			logger.logRed(ustring("connection Failed"));
			return false;
		}

		if(botstream)
			delete botstream;
		botstream = new UnrealStream(  DataInputStream::create(connection->get_input_stream()) ,
                    DataOutputStream::create(connection->get_output_stream())
                );
	
    logger.log("connecting...", true);
 // We read the response of the server
	string buffer ="";
	try{
		buffer = botstream->nextMessage();
	}
	catch(Glib::Error& e){
		logger.logRed(ustring("connection Failed: ") + e.what());
		connection->close();
		return false;
	}
//cout << "received: " << buffer << std::endl;
    if (buffer == "HELLO_BOT"){
        state= connected;
        logger.logGreen( "Connected; hello received" );
        botstream->putCommand("READY");
		if(state & awaiting_connect)
			state = running;
		else
			state = connected;
		logger.logGreen("Connection Succeeded", true);
        return  true;
    }else{
        logger.logRed("failed to connect properly.\n received: ");
		connection->close(); 
        logger.logRed(buffer);
        return false;
    }
}


